package com.bpzj.mybatis;

import com.bpzj.mybatis.mapper.AuthorMapper;
import com.bpzj.mybatis.mapper.BlogMapper;
import com.bpzj.mybatis.model.Author;
import com.bpzj.mybatis.model.Blog;
import com.bpzj.mybatis.result.BlogAuthorMap;
import com.bpzj.mybatis.typehandler.ListTypeHandler;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class OnlyUseMybatisByHand {

  public static void main(String[] args) {
//    customTypeHandler();
//     testCache();
    whyMapperCanNotReload();
  }

  /**
   * mapper 接口方法为什么不能重载? <br>
   * 这是一个老的面试题, 因为 xml 中的 statement ID 是以 namespace + method name 确定唯一性的, <br>
   * 所以在相同的 namespace中, 不能出现 id相同的 statement <br>
   * <p>
   * 但是在mapper接口中, 可以出现重载的方法, 然后把这两个方法绑定到 同一个 statement, 如下面的例子
   */
  public static void whyMapperCanNotReload() {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactoryUseJavaClass();
    SqlSession sqlSession = sqlSessionFactory.openSession(false);
    AuthorMapper mapper = sqlSession.getMapper(AuthorMapper.class);
    Author author = mapper.selectByPrimaryKey(1);
    author = mapper.selectByPrimaryKey("name");


  }



  /**
   * mybatis 一级缓存
   */
  public static void testCache() {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactoryUseJavaClass();
    SqlSession sqlSession = sqlSessionFactory.openSession(false);
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    // 调用两此方法，发现打印了一次sql语句，说明查询了一次sql
    List<Blog> blog = mapper.selectAll();
    List<Blog> blog1 = mapper.selectAll();
    sqlSession.close();

    // 查询后，关闭Session，再新建 Session 重新查询，发现打印了两次
    // 说明 一级缓存是基于 SqlSession 的, Session关闭后，缓存消失
    sqlSession = sqlSessionFactory.openSession(false);
    mapper = sqlSession.getMapper(BlogMapper.class);
    mapper.exportAll();
    sqlSession.close();
    sqlSession = sqlSessionFactory.openSession(false);
    mapper = sqlSession.getMapper(BlogMapper.class);
    mapper.exportAll();
    sqlSession.close();
  }

  /**
   * 自定义 TypeHandler
   */
  public static void customTypeHandler() {
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactoryUseJavaClass();
    SqlSession sqlSession = sqlSessionFactory.openSession(false);
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    List<List<String>> lists = mapper.exportAll();
    System.out.println(lists);
  }

  /**
   * 使用 java 代码获取 SqlSessionFactory
   */
  private static SqlSessionFactory getSqlSessionFactoryUseJavaClass() {
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    Configuration config = new Configuration();

    // 对应xml文件  <transactionManager type="JDBC"/>
    TransactionFactory transactionFactory = new JdbcTransactionFactory();

    // 对应xml文件
    //           <dataSource type="POOLED">
    //                <property name="driver" value="${jdbc.driverClassName}"/>
    //                <property name="url" value="${jdbc.url}"/>
    //                <property name="username" value="${jdbc.username}"/>
    //                <property name="password" value="${jdbc.password}"/>
    //            </dataSource>
    MysqlDataSource datasource = new MysqlDataSource();
    datasource.setUrl("jdbc:mysql://192.168.137.10:3306/test");
    datasource.setUser("root");
    datasource.setPassword("minmin");
    // 对应
    //      <!--配置运行环境-->
    //      <environments default="development">
    //          <environment id="development">
    //              <!--数据库类型-->
    //              <transactionManager type="JDBC"/>
    //              <dataSource type="POOLED">
    //                  ...
    //              </dataSource>
    //          </environment>
    //      </environments>
    Environment environment = new Environment("dev", transactionFactory, datasource);

    config.setMapUnderscoreToCamelCase(true);
    config.addMapper(BlogMapper.class);
    config.addMapper(AuthorMapper.class);

    config.setEnvironment(environment);
    // 添加 自定义的 typeHandler
    config.getTypeHandlerRegistry().register(ListTypeHandler.class);

    // 配置 日志实现为 SLF4J
    config.setLogImpl(Slf4jImpl.class);

    return builder.build(config);
  }

  /**
   * 从xml文件解析出 SqlSessionFactory
   */
  private static SqlSessionFactory getSqlSessionFactoryUseXml() throws IOException {
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    return sqlSessionFactory;
  }

}
